using System;
using System.Collections.Generic;

namespace IQIGame.Onigao.Framework
{
    public class SType
    {

        public const byte NULL = 0;
        public const byte BOOLEAN = unchecked(1 << 4);
        public const byte BYTE = unchecked(2 << 4);
        public const byte UBYTE = unchecked(3 << 4);
        public const byte SHORT = unchecked(4 << 4);
        public const byte USHORT = unchecked(5 << 4);
        public const byte INT = unchecked(6 << 4);
        public const byte UINT = unchecked(7 << 4);
        public const byte FLOAT = unchecked(8 << 4);
        public const byte DOUBLE = unchecked(9 << 4);
        public const byte LONG = unchecked(10 << 4);
        public const byte STRING = unchecked(11 << 4);
        public const byte BYTES = unchecked(12 << 4);
        public const byte MAP = unchecked(13 << 4);
        public const byte LIST = unchecked(14 << 4);
        public const byte POD = unchecked(15 << 4);

        private static Dictionary<string, string> GetTypeMap()
        {
            return new Dictionary<string, string>
            {
                { "boolean", "bool" },
                { "byte", "sbyte" },
                { "ubyte", "byte" },
                { "short", "short" },
                { "ushort", "ushort" },
                { "int", "int" },
                { "uint", "uint" },
                { "float", "float" },
                { "double", "double" },
                { "long", "long" },
                { "string", "string" },
                { "bytes", "byte[]" }
            };
        }


        public static string CodeGenSOutputStream()
        {
            string codeStr = "";
            string writeMapCode = @"
                public void Write_map_{k}_{v}(Dictionary<{K}, {V}> value)
                {
                    if (value == null)
                    {
                        _buffer.WriteNull();
                        return;
                    }
                    _buffer.WriteSize((uint)value.Count, SType.MAP);
                    if (value.Count > 0)
                    {
                        foreach (KeyValuePair<{K}, {V}> entry in value)
                        {
                            _buffer.Write_{k}(entry.Key);
                            _buffer.Write_{v}(entry.Value);
                        }
                    }
                }
                ";
            foreach (var ek in GetTypeMap())
            {
                foreach (var ev in GetTypeMap())
                {
                    string tmpCode1 = writeMapCode;
                    tmpCode1 = tmpCode1.Replace("{k}", ek.Key);
                    tmpCode1 = tmpCode1.Replace("{v}", ev.Key);
                    tmpCode1 = tmpCode1.Replace("{K}", ek.Value);
                    tmpCode1 = tmpCode1.Replace("{V}", ev.Value);
                    codeStr += tmpCode1;
                }
            }


            string writeMapCode1 = @"
                public void Write_map_{t}_pod<V>(Dictionary<{T}, V> map) where V : IPOD
                {
                    if (map == null)
                    {
                        _buffer.WriteNull();
                        return;
                    }
                    _buffer.WriteSize((uint)map.Count, SType.MAP);
                    if (map.Count > 0)
                    {
                        foreach (KeyValuePair<{T}, V> entry in map)
                        {
                            _buffer.Write_{t}(entry.Key);
                            Write_pod(entry.Value);
                        }
                    }
                }
                ";
            foreach (var ek in GetTypeMap())
            {
                string tmpCode1 = writeMapCode1;
                tmpCode1 = tmpCode1.Replace("{t}", ek.Key);
                tmpCode1 = tmpCode1.Replace("{T}", ek.Value);
                codeStr += tmpCode1;
            }


            string writeMapCode2 = @"
                public void Write_map_pod_{t}<K>(Dictionary<K, {T}> map) where K : IPOD
                {
                    if (map == null)
                    {
                        _buffer.WriteNull();
                        return;
                    }
                    _buffer.WriteSize((uint)map.Count, SType.MAP);
                    if (map.Count > 0)
                    {
                        foreach (KeyValuePair<K, {T}> entry in map)
                        {
                            Write_pod(entry.Key);
                            _buffer.Write_{t}(entry.Value);
                        }
                    }
                }
                ";
            foreach (var ek in GetTypeMap())
            {
                string tmpCode1 = writeMapCode2;
                tmpCode1 = tmpCode1.Replace("{t}", ek.Key);
                tmpCode1 = tmpCode1.Replace("{T}", ek.Value);
                codeStr += tmpCode1;
            }


            string writeListCode = @"
                public void Write_list_{t}(List<{T}> value)
                {
                    if (value == null)
                    {
                        _buffer.WriteNull();
                        return;
                    }
                    _buffer.WriteSize((uint)value.Count, SType.LIST);
                    if (value.Count > 0)
                    {
                        foreach ({T} v in value)
                        {
                            _buffer.Write_{t}(v);
                        }
                    }
                }
                ";
            foreach (var ek in GetTypeMap())
            {
                string tmpCode1 = writeListCode;
                tmpCode1 = tmpCode1.Replace("{t}", ek.Key);
                tmpCode1 = tmpCode1.Replace("{T}", ek.Value);
                codeStr += tmpCode1;
            }


            return codeStr;
        }

        public static string CodeGenSInputStream()
        {
            string codeStr = "";
            string readMapCode = @"
                public Dictionary<{K}, {V}> Read_map_{k}_{v}()
                {
                    byte identity = _buffer.Read();
                    if (identity == SType.NULL)
                    {
                        return null;
                    }

                    if ((byte)(identity & 0xf0) != SType.MAP)
                    {
                        throw new Exception(""can't convert to map"");
                    }
                    uint length = _buffer.ReadSize(identity);
                    Dictionary<{K}, {V}> map = new Dictionary<{K}, {V}>((int)length);
                    for (uint i = 0; i < length; i++)
                    {
                        map.Add(_buffer.Read_{k}(), _buffer.Read_{v}());
                    }
                    return map;
                }
                ";
            foreach (var ek in GetTypeMap())
            {
                foreach (var ev in GetTypeMap())
                {
                    string tmpCode1 = readMapCode;
                    tmpCode1 = tmpCode1.Replace("{k}", ek.Key);
                    tmpCode1 = tmpCode1.Replace("{v}", ev.Key);
                    tmpCode1 = tmpCode1.Replace("{K}", ek.Value);
                    tmpCode1 = tmpCode1.Replace("{V}", ev.Value);
                    codeStr += tmpCode1;
                }
            }


            string readMapCode1 = @"
                public Dictionary<{K}, {V}> Read_map_{k}_{v}(Dictionary<{K}, {V}> map)
                {
                    byte identity = _buffer.Read();
                    if (identity == SType.NULL)
                    {
                        return null;
                    }

                    if ((byte)(identity & 0xf0) != SType.MAP)
                    {
                        throw new Exception(""can't convert to map"");
                    }
                    uint length = _buffer.ReadSize(identity);
                    for (uint i = 0; i < length; i++)
                    {
                        map.Add(_buffer.Read_{k}(), _buffer.Read_{v}());
                    }
                    return map;
                }
                ";
            foreach (var ek in GetTypeMap())
            {
                foreach (var ev in GetTypeMap())
                {
                    string tmpCode1 = readMapCode1;
                    tmpCode1 = tmpCode1.Replace("{k}", ek.Key);
                    tmpCode1 = tmpCode1.Replace("{v}", ev.Key);
                    tmpCode1 = tmpCode1.Replace("{K}", ek.Value);
                    tmpCode1 = tmpCode1.Replace("{V}", ev.Value);
                    codeStr += tmpCode1;
                }
            }


            string readListCode = @"
                public List<{T}> Read_list_{t}()
                {
                    byte identity = _buffer.Read();
                    if (identity == SType.NULL)
                    {
                        return null;
                    }
                    if ((byte)(identity & 0xf0) != SType.LIST)
                    {
                        throw new Exception(""can't convert to list"");
                    }
                    uint length = _buffer.ReadSize(identity);
                    List<{T}> list = new List<{T}>((int)length);
                    for (uint i = 0; i < length; i++)
                    {
                        list.Add(_buffer.Read_{t}());
                    }
                    return list;
                }
                ";
            foreach (var ek in GetTypeMap())
            {
                string tmpCode1 = readListCode;
                tmpCode1 = tmpCode1.Replace("{t}", ek.Key);
                tmpCode1 = tmpCode1.Replace("{T}", ek.Value);
                codeStr += tmpCode1;
            }

            string readListCode1 = @"
                public List<{T}> Read_list_{t}(List<{T}> list)
                {
                    byte identity = _buffer.Read();
                    if (identity == SType.NULL)
                    {
                        return null;
                    }
                    if ((byte)(identity & 0xf0) != SType.LIST)
                    {
                        throw new Exception(""can't convert to list"");
                    }
                    uint length = _buffer.ReadSize(identity);
                    for (uint i = 0; i < length; i++)
                    {
                        list.Add(_buffer.Read_{t}());
                    }
                    return null;
                }
                ";
            foreach (var ek in GetTypeMap())
            {
                string tmpCode1 = readListCode1;
                tmpCode1 = tmpCode1.Replace("{t}", ek.Key);
                tmpCode1 = tmpCode1.Replace("{T}", ek.Value);
                codeStr += tmpCode1;
            }


            string readMap_K_POD = @"
                public Dictionary<{T}, V> Read_map_{t}_pod<V>(Func<V> factory) where V : IPOD
                {
                    byte identity = _buffer.Read();
                    if (identity == SType.NULL)
                    {
                        return null;
                    }
                    if ((byte)(identity & 0xf0) != SType.MAP)
                    {
                        throw new Exception(""can't convert to map"");
                    }
                    uint length = _buffer.ReadSize(identity);
                    Dictionary<{T}, V> map = new Dictionary<{T}, V>((int)length);
                    for (uint i = 0; i < length; i++)
                    {
                        map.Add(_buffer.Read_{t}(), Read_pod<V>(factory));
                    }
                    return map;
                }
                ";
            foreach (var ek in GetTypeMap())
            {
                string tmpCode1 = readMap_K_POD;
                tmpCode1 = tmpCode1.Replace("{t}", ek.Key);
                tmpCode1 = tmpCode1.Replace("{T}", ek.Value);
                codeStr += tmpCode1;
            }

            string readMap_K_POD1 = @"
                public Dictionary<{T}, V> Read_map_{t}_pod<V>(Dictionary<{T}, V> map, Func<V> factory) where V : IPOD
                {
                    byte identity = _buffer.Read();
                    if (identity == SType.NULL)
                    {
                        return null;
                    }
                    if ((byte)(identity & 0xf0) != SType.MAP)
                    {
                        throw new Exception(""can't convert to map"");
                    }
                    uint length = _buffer.ReadSize(identity);
                    for (uint i = 0; i < length; i++)
                    {
                        map.Add(_buffer.Read_{t}(), Read_pod<V>(factory));
                    }
                    return map;
                }
                ";
            foreach (var ek in GetTypeMap())
            {
                string tmpCode1 = readMap_K_POD1;
                tmpCode1 = tmpCode1.Replace("{t}", ek.Key);
                tmpCode1 = tmpCode1.Replace("{T}", ek.Value);
                codeStr += tmpCode1;
            }


            string readMap_POD_V = @"
                public Dictionary<K, {T}> Read_map_pod_{t}<K>(Func<K> factory) where K : IPOD
                {
                    byte identity = _buffer.Read();
                    if (identity == SType.NULL)
                    {
                        return null;
                    }
                    if ((byte)(identity & 0xf0) != SType.MAP)
                    {
                        throw new Exception(""can't convert to map"");
                    }
                    uint length = _buffer.ReadSize(identity);
                    Dictionary<K, {T}> map = new Dictionary<K, {T}>((int)length);
                    for (uint i = 0; i < length; i++)
                    {
                        map.Add(Read_pod<K>(factory), _buffer.Read_{t}());
                    }
                    return map;
                }
                ";
            foreach (var ek in GetTypeMap())
            {
                string tmpCode1 = readMap_POD_V;
                tmpCode1 = tmpCode1.Replace("{t}", ek.Key);
                tmpCode1 = tmpCode1.Replace("{T}", ek.Value);
                codeStr += tmpCode1;
            }

            string readMap_POD_V1 = @"
                public Dictionary<K, {T}> Read_map_pod_{t}<K>(Dictionary<K, {T}> map, Func<K> factory) where K : IPOD
                {
                    byte identity = _buffer.Read();
                    if (identity == SType.NULL)
                    {
                        return null;
                    }
                    if ((byte)(identity & 0xf0) != SType.MAP)
                    {
                        throw new Exception(""can't convert to map"");
                    }
                    uint length = _buffer.ReadSize(identity);
                    for (uint i = 0; i < length; i++)
                    {
                        map.Add(Read_pod<K>(factory), _buffer.Read_{t}());
                    }
                    return map;
                }
                ";
            foreach (var ek in GetTypeMap())
            {
                string tmpCode1 = readMap_POD_V1;
                tmpCode1 = tmpCode1.Replace("{t}", ek.Key);
                tmpCode1 = tmpCode1.Replace("{T}", ek.Value);
                codeStr += tmpCode1;
            }

            return codeStr;
        }
    }

}
